package com.globalwave.rule.engine;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;

import com.globalwave.rule.AccLimitJDBCDAO;
import com.globalwave.rule.entity.RuleAction;
import com.globalwave.rule.entity.RuleLimit;



/**
 * 规则树对象，用于构建规则树和规则演算。
 * 
 * @author 陈向荣
 * @version 1.0
 * 
 * Modification history:
 * {date} Modified by {who} & {why} & {what} is modified
 */
public class RuleTree {
    
    private AccLimitJDBCDAO accLimitJDBCDAO  ; 
    
    private Log log = LogFactoryImpl.getLog(this.getClass()) ;
    
    final public static Long rootId = - 1L;
    private LimitNode root ;
    private Map<Long, LimitNode> nodeMap = null ;
    private List<ResultAction> actions = null ;
        
    public RuleTree() {
        
        nodeMap = new HashMap<Long, LimitNode>() ;
        
        root = new LimitNode() ;
        root.setId(RuleTree.rootId) ;
        //root.setLimitName("root") ;
        //root.setFactorCd(FACTOR_CD_FIX) ;
        
        addNode(root, null) ;
    }
    
    private void addNode(LimitNode limitNode, Long parentId) {
        nodeMap.put(limitNode.getId(),limitNode) ;
        
        // limitId = -1 is root node，非根条件要找他的父条件，并作为其子条件
        if (limitNode.getId() != RuleTree.rootId) {
            LimitNode parentNode = nodeMap.get(parentId) ;
            
            if (parentNode != null) {
                parentNode.addChildren(limitNode) ;
            }
        }
        
    }
    
    private void addAction(RuleAction ruleAction) {
    	if (actions == null) {
    		actions = new ArrayList<ResultAction>() ;
    	}
    	actions.add(new ResultAction(ruleAction)) ;
    }
    
    /**
     * 根据因子值，计算规则树的输出值
     * 
     * @param vars
     * @return
     * @throws Exception
     */
    public boolean evaluate(Map<String, Object> vars) throws Exception {
        return root.evaluate(vars) ;
    }

    public void trigger(Map<String, Object> vars) throws Exception {
    	
    	boolean result = evaluate(vars);
    	vars.put("$result", result) ;
    	if (result) {
    		handleResult(vars) ;
    	}
    }
    private void handleResult(Map<String, Object> vars) throws Exception {
    	if (actions == null) {
    		return ;
    	}
    	
    	for (int i = 0 ; i < actions.size() ; i ++) {
    		actions.get(i).handle(vars) ;
    	}
    }
    
    
    /**
     * 根据规则标识，构建规则树。
     * 
     * @param ruleId 规则标识
     * @throws Exception
     */
    public void build(String ruleId) throws Exception {
        
        LimitNode cacheRoot = null;//(LimitNode) this.getCache(CACHE_build).get(ruleId);
        
        if (cacheRoot != null) { // 缓存中有数据，从中存出
            this.root = cacheRoot ;
            return ;
        }
                
        if (accLimitJDBCDAO == null) {
            accLimitJDBCDAO = new AccLimitJDBCDAO() ;
        }

        List<RuleLimit> limits = accLimitJDBCDAO.findByRuleId(ruleId) ;
        List<RuleAction> actions = null;//accLimitJDBCDAO.findByRuleId(ruleId) ;
        
        build(limits, actions) ;    
        
        //this.getCache(CACHE_build).put(ruleId, this.root);
    }
    
    /**
     * 根据条件，构建规则树。
     * 
     * @param limits 条件组
     * @throws Exception
     */
    public RuleTree build(List<RuleLimit> limits, List<RuleAction> actions) throws Exception {
        
        for (RuleLimit limitCR:limits) {          
            LimitNode limitNode = new LimitNode(limitCR) ;

            addNode(limitNode, limitCR.getPro_limit_node_id()) ;
        }
        
        if (actions != null) {
	        for (RuleAction action:actions) {
	        	addAction(action) ;
	        }
        }
        return this ;
    }
    
}
